package model;


import java.util.ArrayList;
import java.util.Collection;

import model.auxillary.Parameter;
import model.auxillary.ParameterList;
import model.auxillary.ParameterList.ParameterType;
import view.IObserver;

/**
 * A {@code Process} is the most abstract version to model a production
 * process. It manages parameters and can be observerd by observers. It also
 * has the role of an observer. It obervers the process' parameters.
 * @author Oliver Eckstein
 *
 */
public abstract class Process implements IObservable, IObserver {
	
	/**
	 * The part process' name.
	 */
	protected String name;
	
	/**
	 * An identifying id for this process.
	 */
	protected String id;
	
	/**
	 * To indicate whether this {@code Process} was calculated or not.
	 * It's value is {@code true} when it was calculated, {@code false}
	 * otherwise. 
	 */
	protected boolean calculated;
	
	/**
	 * To indicate whether the calculation of this {@code Process} caused an
	 * error. {@code true} when calculation caused an error, {@code false}
	 * otherwise.
	 */
	protected boolean error;
	
	/**
	 * To indicate that the calculation was aborted. This does not always
	 * mean that an error occurred. {@code true} when calculation was aborted,
	 * {@code false} otherwise.
	 */
	protected boolean aborted;
	
	/**
	 * The process' observers.
	 */
	private Collection<IObserver> observers;
	
	/**
	 * The process' parameters handled by a {@code ParameterList} object.
	 */
	protected ParameterList parameters;
	
	/**
	 * To create a new {@code Process}.
	 * @param name the name of the process.
	 * @param id a unique ID that identifies this process.
	 */
	public Process (String name, String id) {
		this.name = name;
		this.id = id;
		calculated = false;
		error = false;		
		observers = new ArrayList<IObserver>();
		parameters = new ParameterList(this);		
	}
	
	/**
	 * To get the name of this {@code Process}
	 * @return the name.
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * To get all parameters of this {@code Process}.
	 * @return the parameters.
	 */
	public ParameterList getParameters() {
		return parameters;
	}
	
	/**
	 * To set a name for this {@code Process}.
	 * @param name the name.
	 */
	public void setName(String name) {		
		this.name = name;
		notifyObservers();
	}
	
	/**
	 * To get a parameter by it's abbreviation and type.
	 * @param abbreviation the parameter's abbreviation.
	 * @param type the type of parameter.
	 * @return the parameter.
	 */
	public Parameter getParameter(String abbreviation, ParameterType type) {
		return parameters.getParameter(type, abbreviation);
	}
	
	/**
	 * To get the number of parameters that must be set by the user.
	 * @return the number of user dependent parameters.
	 */
	public int getUserSetParametersCount() {
		return parameters.getUserSetParametersCount();
	}

	/**
	 * Whether all parameters that have to be set by the user are set or not.
	 * @return {@code true} when all parameters are set, {@code false}
	 * otherwise.
	 */
	public boolean allSet() {
		return parameters.allSet();
	}
    
    /**
	 * To get a parameter by it's unique ID.	 
	 * @param parameterID the parameter's ID.
	 * @return the parameter.
	 */
	public Parameter getParameter(String parameterID) {
		return parameters.getParameter(parameterID);
	}
    
    /**
     * To add the process' defining parameters.
     */
    protected abstract void addParameters();
    
    /**
	 * To get the unique ID of this {@code Process}.
	 * @return the unique ID.
	 */
    public String getID() {
    	return id;
    }
	
	@Override
    public void registerObserver(IObserver observer)
    {
        if(!observers.contains(observer)) {
        	observers.add(observer);	
        }		
    }
    
    @Override
    public void removeObserver(IObserver observer)
    {
        if(observers.contains(observer))
        {
            observers.remove(observer);            
        }
    }
    
    @Override
    public void notifyObservers()
    {   
        for(IObserver observer : observers)
        {
            observer.update();                    
        }        
    }
    
    @Override
    public void update() {
    	calculated = false;    	
    	notifyObservers();    	
    }
    
    @Override
    public String toString() {
    	return name;
    }
    
    /**
     * To get all {@code IObserver} interfaces of this {@code Process}. 
     * @return the observers.
     */
    public Collection<IObserver> getObservers() {
    	return observers;
    }
}
